﻿using System;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OpenId;
using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration;
using DotNetOpenAuth.OpenId.RelyingParty;
using System.Web.Mvc;
using Omu.Encrypto;
using Uber.Core.Security;
using Uber.Core.Service;
using Uber.WebUI.Models;

namespace Uber.WebUI.Controllers
{
    [HandleError]
    public class AccountController : Controller
    {
        private readonly IFormsAuthentication formsAuth;
        private readonly IAccounts accounts;
        private static readonly OpenIdRelyingParty Openid = new OpenIdRelyingParty();

        public AccountController(IFormsAuthentication formsAuth, IAccounts accounts)
        {
            this.formsAuth = formsAuth;
            this.accounts = accounts;
        }

        [ValidateInput(false)]
        public ActionResult Authenticate(string returnUrl, string oi)
        {
            var response = Openid.GetResponse();
            if (response == null)
            {
                // Stage 2: user submitting Identifier
                if (string.IsNullOrEmpty(oi))
                {
                    ModelState.AddModelError("oid", "no OpenID identifier was provided");
                    return View("LogIn");
                }
                Identifier id;
                if (Identifier.TryParse(oi, out id))
                {
                    try
                    {
                        var req = Openid.CreateRequest(oi);
                        req.AddExtension(new ClaimsRequest
                        {
                            Email = DemandLevel.Require,
                            FullName = DemandLevel.Request,
                        });
                        return req.RedirectingResponse.AsActionResult();

                    }
                    catch (ProtocolException ex)
                    {
                        ViewData["Message"] = ex.Message;
                        return View("LogIn");
                    }
                }
                ModelState.AddModelError("oid", "Invalid identifier");
                return View("LogIn");
            }
            // Stage 3: OpenID Provider sending assertion response
            switch (response.Status)
            {
                case AuthenticationStatus.Authenticated:
                    var email = "";
                    var name = "";

                    var sreg = response.GetExtension<ClaimsResponse>();
                    if (sreg != null && sreg.MailAddress != null)
                    {
                        email = sreg.MailAddress.Address;
                        name = sreg.MailAddress.User;
                    }
                    if (sreg != null && !string.IsNullOrEmpty(sreg.FullName))
                        name = sreg.FullName;

                    var id = accounts.OpenIdLogIn(response.ClaimedIdentifier, email, name);

                    formsAuth.SignIn(id.ToString(), true, "user");


                    if (!string.IsNullOrEmpty(returnUrl))
                        return Redirect(returnUrl);

                    return RedirectToAction("Index", "Home");
                case AuthenticationStatus.Canceled:
                    ModelState.AddModelError("oid", "Canceled at provider");
                    return View("LogIn");
                case AuthenticationStatus.Failed:
                    ModelState.AddModelError("oid", response.Exception.Message);
                    return View("LogIn");
            }
            return new EmptyResult();
        }

        public ActionResult LogIn(string reason)
        {
            if (reason != null)
                ViewData["reason"] = reason;
            return View();
        }

        [HttpPost]
        public ActionResult LogIn(string email, string password, bool rememberMe, string returnUrl)
        {
            var id = accounts.LogIn(email, password);
            if (id == 0)
            {
                ModelState.AddModelError("alogin", "Login or Password not correct, please try again");
                return View();
            }

            if (id == -1)
                return RedirectToAction("Created", "Success", new { email });

            formsAuth.SignIn(id.ToString(), rememberMe, "user");

            if (!string.IsNullOrEmpty(returnUrl))
                return Redirect(System.Web.HttpUtility.UrlDecode(returnUrl));

            return RedirectToAction("Index", "Home");

        }

        public ActionResult LogOut()
        {
            formsAuth.SignOut();
            return RedirectToAction("Index", "Home");
        }

        public ActionResult RequestPasswordReset()
        {
            return View();
        }

        [HttpPost]
        [CaptchaValidator]
        public ActionResult RequestPasswordReset(PassResetInput input, bool captchaValid)
        {
            while (true)
            {
                if (!ModelState.IsValid)
                    break;
                if (!captchaValid)
                {
                    ModelState.AddModelError("captcha", "captcha not valid");
                    break;
                }
                if (!accounts.EmailExists(input.Email))
                {
                    ModelState.AddModelError("Email", "this email isn't registered on this site");
                    break;
                }

                accounts.RequestRecover(input.Email);
                return View("RecoverRequested");
            }
            return View();
        }

        public ActionResult ResetPassword(long code, string email)
        {
            if (accounts.IsRecoverValid(code, email))
                return View(new ResetPasswordInput { Code = code, Email = email });
            return View("Info",
                        new InfoDisplay
                            {
                                Info = @"this recovery link is not valid anymore, 
                                        if you have forgotten your password please go to the login screen 
                                        and click the link 'forgotten password'"
                            });
        }

        [HttpPost]
        public ActionResult ResetPassword(ResetPasswordInput input)
        {
            if (!ModelState.IsValid) return View(input);
            if (!accounts.ResetPassword(input.Email, Convert.ToInt64(input.Code), input.NewPassword))
            {
                ModelState.AddModelError("", "Invalid recovery link");
                return View(input);
            }
            return View("info", new InfoDisplay { Info = "your password has been changed" });
        }

        public ActionResult Unsubscribe(long id, string q)
        {
            var a = Fa.Account.Get(id);
            var h = new Hasher { SaltSize = 13 };
            if (h.CompareStringToHash(a.CreationDate.ToString(), System.Web.HttpUtility.HtmlDecode(q).Replace(" ","+")))
            {
                Fa.Account.SaveMailSettings(false, false, a.Id);
                return View();
            }
            return View("PageNotFound");
        }
    }
}


